/**
 ******************************************************************************
 * @file    tpad.c
 * @author  正点原子@ALIENTEK
 * @version 1.0
 * @date    2022-8-26
 * @brief   电容按键触摸实验源文件
 ******************************************************************************
 * @attention
 *
 * Copyright(C) 广州市星翼电子科技有限公司 2009-2019
 *
 * 本程序只供学习使用，未经作者许可，不得用于其它任何用途
 */

#include <tpad.h>
#include <delay.h>

#define TPAD_ARR_MAX_VAL 0XFFFF //最大的ARR值

// 空载的时候(没有手按下),计数器需要的时间
vu16 tpad_default_val = 0;

/**
 * @brief  定时器2通道2输入捕获配置
 * @param  arr: TIM5 自动重装载值。
 *              此参数必须是介于 0x0000 和 0xFFFF 之间的数字
 * @param  psc: TIM5 预分频系数。
 *              此参数可以是 0x0000 和 0xFFFF 之间的数字
 * @retval None
 */
void TIM5_CH2_Cap_Init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_ICInitTypeDef TIM5_ICInitStructure;

    // 外设时钟使能
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    // 初始化GPIO
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING; // 佛空输入
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 初始化 TIM5
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period        = arr;
    TIM_TimeBaseStructure.TIM_Prescaler     = psc;
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);

    // 初始化定时器捕获通道
    TIM5_ICInitStructure.TIM_Channel     = TIM_Channel_2;
    TIM5_ICInitStructure.TIM_ICFilter    = 0x03;
    TIM5_ICInitStructure.TIM_ICPolarity  = TIM_ICPolarity_Rising;
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInit(TIM5, &TIM5_ICInitStructure);

    TIM_Cmd(TIM5, ENABLE);
}

/**
 * @brief  复位一次
 * @param  None
 * @retval None
 */
void TPAD_Reset(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能PA端口时钟

    //设置GPIOA.1为推挽使出
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;       // PA1 端口配置
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP; // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_ResetBits(GPIOA, GPIO_Pin_1); // PA.1输出0,放电

    // 需要引入 delay.h
    delay_ms(5);

    TIM_SetCounter(TIM5, 0);                                 // 归0
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC2 | TIM_IT_Update); // 清除中断标志

    //设置GPIOA.1为浮空输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/**
 * @brief  得到定时器捕获值
 * @note   如果超时,则直接返回定时器的计数值
 * @param  None
 * @retval 定时器捕获值
 */
u16 TPAD_Get_Val(void)
{
    TPAD_Reset();

    while (TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET) //等待捕获上升沿
    {
        //超时了,直接返回CNT的值
        if (TIM_GetCounter(TIM5) > TPAD_ARR_MAX_VAL - 500)
        {
            return TIM_GetCounter(TIM5);
        }
    }

    return TIM_GetCapture2(TIM5);
}

/**
 * @brief  电容触摸按键初始化
 * @param  psc: 定时器初始化预分频系数
 * @retval 0：初始化成功。1：初始化失败。
 */
u8 TPAD_init(u8 psc)
{
    u16 buf[10];
    u16 temp;
    u8 j, i;

    TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL, psc - 1); // 以1Mhz的频率计数

    for (i = 0; i < 10; i++) // 连续读取10次
    {
        buf[i] = TPAD_Get_Val();
        delay_ms(10);
    }

    for (i = 0; i < 9; i++) // 排序
    {
        for (j = i + 1; j < 10; j++)
        {
            if (buf[i] > buf[j]) // 升序排列
            {
                temp   = buf[i];
                buf[i] = buf[j];
                buf[j] = temp;
            }
        }
    }

    temp = 0;

    // 取中间的6个数据进行平均
    for (i = 2; i < 8; i++)
    {
        temp += buf[i];
    }
    tpad_default_val = temp / 6;

    // USART_printf(USART1, "tpad_default_val:%d\r\n", tpad_default_val);

    // 初始化遇到超过 TPAD_ARR_MAX_VAL/2 的数值,不正常!
    if (tpad_default_val > TPAD_ARR_MAX_VAL / 2)
    {
        return 1;
    }

    return 0;
}

/**
 * @brief  读取n次,取最大值
 * @param  n: 连续获取的次数
 * @retval n次读数里面读到的最大读数值
 */
u16 TPAD_Get_MaxVal(u8 n)
{
    u16 temp = 0;
    u16 res  = 0;

    while (n--)
    {
        temp = TPAD_Get_Val(); //得到一次值
        if (temp > res)
        {
            res = temp;
        }
    }

    return res;
}

/**
 * @brief  扫描触摸按键
 * @param  mode: 是否支持连续触发。
 *   该参数可以是以下值之一。
 *      @arg 0: 不支持连续触发(按下一次必须松开才能按下一次)
 *      @arg 1: 支持连续触发(可以一直按下)
 * @retval 0: 没有按下; 1: 有按下。
 */
u8 TPAD_Scan(u8 mode)
{
    static u8 keyen = 0; // 0,可以开始检测;>0,还不能开始检测
    u8 res          = 0;
    u8 sample       = 3; // 默认采样次数为3次
    u16 rval;

    if (mode)
    {
        sample = 6; // 支持连按的时候，设置采样次数为6次
        keyen  = 0; // 支持连按
    }

    rval = TPAD_Get_MaxVal(sample);

    if (rval > (tpad_default_val + TPAD_GATE_VAL)) // 大于tpad_default_val+TPAD_GATE_VAL,有效
    {
        if (keyen == 0) res = 1; // keyen==0,有效
        keyen = 3;               //至少要再过3次之后才能按键有效
    }

    if (keyen)
    {
        keyen--;
    }

    return res;
}
